1 /*
2 * Copyright (C) 2008 The Guava Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.google.common.primitives;
18
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkElementIndex;
21 import static com.google.common.base.Preconditions.checkNotNull;
22 import static com.google.common.base.Preconditions.checkPositionIndexes;
23
24 import com.google.common.annotations.Beta;
25 import com.google.common.annotations.GwtCompatible;
26 import com.google.common.annotations.GwtIncompatible;
27 import com.google.common.base.Converter;
28
29 import java.io.Serializable;
30 import java.util.AbstractList;
31 import java.util.Arrays;
32 import java.util.Collection;
33 import java.util.Collections;
34 import java.util.Comparator;
35 import java.util.List;
36 import java.util.RandomAccess;
37
38 /**
39 * Static utility methods pertaining to {@code short} primitives, that are not
40 * already found in either {@link Short} or {@link Arrays}.
41 *
42 * <p>See the Guava User Guide article on <a href=
43 * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained">
44 * primitive utilities</a>.
45 *
46 * @author Kevin Bourrillion
47 * @since 1.0
48 */
49 @GwtCompatible(emulated = true)
50 public final class Shorts {
51 private Shorts() {}
52
53 /**
54 * The number of bytes required to represent a primitive {@code short}
55 * value.
56 */
57 public static final int BYTES = Short.SIZE / Byte.SIZE;
58
59 /**
60 * The largest power of two that can be represented as a {@code short}.
61 *
62 * @since 10.0
63 */
64 public static final short MAX_POWER_OF_TWO = 1 << (Short.SIZE - 2);
65
66 /**
67 * Returns a hash code for {@code value}; equal to the result of invoking
68 * {@code ((Short) value).hashCode()}.
69 *
70 * @param value a primitive {@code short} value
71 * @return a hash code for the value
72 */
73 public static int hashCode(short value) {
74 return value;
75 }
76
77 /**
78 * Returns the {@code short} value that is equal to {@code value}, if
79 * possible.
80 *
81 * @param value any value in the range of the {@code short} type
82 * @return the {@code short} value that equals {@code value}
83 * @throws IllegalArgumentException if {@code value} is greater than {@link
84 * Short#MAX_VALUE} or less than {@link Short#MIN_VALUE}
85 */
86 public static short checkedCast(long value) {
87 short result = (short) value;
88 if (result != value) {
89 // don't use checkArgument here, to avoid boxing
90 throw new IllegalArgumentException("Out of range: " + value);
91 }
92 return result;
93 }
94
95 /**
96 * Returns the {@code short} nearest in value to {@code value}.
97 *
98 * @param value any {@code long} value
99 * @return the same value cast to {@code short} if it is in the range of the
100 * {@code short} type, {@link Short#MAX_VALUE} if it is too large,
101 * or {@link Short#MIN_VALUE} if it is too small
102 */
103 public static short saturatedCast(long value) {
104 if (value > Short.MAX_VALUE) {
105 return Short.MAX_VALUE;
106 }
107 if (value < Short.MIN_VALUE) {
108 return Short.MIN_VALUE;
109 }
110 return (short) value;
111 }
112
113 /**
114 * Compares the two specified {@code short} values. The sign of the value
115 * returned is the same as that of {@code ((Short) a).compareTo(b)}.
116 *
117 * <p><b>Note for Java 7 and later:</b> this method should be treated as
118 * deprecated; use the equivalent {@link Short#compare} method instead.
119 *
120 * @param a the first {@code short} to compare
121 * @param b the second {@code short} to compare
122 * @return a negative value if {@code a} is less than {@code b}; a positive
123 * value if {@code a} is greater than {@code b}; or zero if they are equal
124 */
125 public static int compare(short a, short b) {
126 return a - b; // safe due to restricted range
127 }
128
129 /**
130 * Returns {@code true} if {@code target} is present as an element anywhere in
131 * {@code array}.
132 *
133 * @param array an array of {@code short} values, possibly empty
134 * @param target a primitive {@code short} value
135 * @return {@code true} if {@code array[i] == target} for some value of {@code
136 * i}
137 */
138 public static boolean contains(short[] array, short target) {
139 for (short value : array) {
140 if (value == target) {
141 return true;
142 }
143 }
144 return false;
145 }
146
147 /**
148 * Returns the index of the first appearance of the value {@code target} in
149 * {@code array}.
150 *
151 * @param array an array of {@code short} values, possibly empty
152 * @param target a primitive {@code short} value
153 * @return the least index {@code i} for which {@code array[i] == target}, or
154 * {@code -1} if no such index exists.
155 */
156 public static int indexOf(short[] array, short target) {
157 return indexOf(array, target, 0, array.length);
158 }
159
160 // TODO(kevinb): consider making this public
161 private static int indexOf(
162 short[] array, short target, int start, int end) {
163 for (int i = start; i < end; i++) {
164 if (array[i] == target) {
165 return i;
166 }
167 }
168 return -1;
169 }
170
171 /**
172 * Returns the start position of the first occurrence of the specified {@code
173 * target} within {@code array}, or {@code -1} if there is no such occurrence.
174 *
175 * <p>More formally, returns the lowest index {@code i} such that {@code
176 * java.util.Arrays.copyOfRange(array, i, i + target.length)} contains exactly
177 * the same elements as {@code target}.
178 *
179 * @param array the array to search for the sequence {@code target}
180 * @param target the array to search for as a sub-sequence of {@code array}
181 */
182 public static int indexOf(short[] array, short[] target) {
183 checkNotNull(array, "array");
184 checkNotNull(target, "target");
185 if (target.length == 0) {
186 return 0;
187 }
188
189 outer:
190 for (int i = 0; i < array.length - target.length + 1; i++) {
191 for (int j = 0; j < target.length; j++) {
192 if (array[i + j] != target[j]) {
193 continue outer;
194 }
195 }
196 return i;
197 }
198 return -1;
199 }
200
201 /**
202 * Returns the index of the last appearance of the value {@code target} in
203 * {@code array}.
204 *
205 * @param array an array of {@code short} values, possibly empty
206 * @param target a primitive {@code short} value
207 * @return the greatest index {@code i} for which {@code array[i] == target},
208 * or {@code -1} if no such index exists.
209 */
210 public static int lastIndexOf(short[] array, short target) {
211 return lastIndexOf(array, target, 0, array.length);
212 }
213
214 // TODO(kevinb): consider making this public
215 private static int lastIndexOf(
216 short[] array, short target, int start, int end) {
217 for (int i = end - 1; i >= start; i--) {
218 if (array[i] == target) {
219 return i;
220 }
221 }
222 return -1;
223 }
224
225 /**
226 * Returns the least value present in {@code array}.
227 *
228 * @param array a <i>nonempty</i> array of {@code short} values
229 * @return the value present in {@code array} that is less than or equal to
230 * every other value in the array
231 * @throws IllegalArgumentException if {@code array} is empty
232 */
233 public static short min(short... array) {
234 checkArgument(array.length > 0);
235 short min = array[0];
236 for (int i = 1; i < array.length; i++) {
237 if (array[i] < min) {
238 min = array[i];
239 }
240 }
241 return min;
242 }
243
244 /**
245 * Returns the greatest value present in {@code array}.
246 *
247 * @param array a <i>nonempty</i> array of {@code short} values
248 * @return the value present in {@code array} that is greater than or equal to
249 * every other value in the array
250 * @throws IllegalArgumentException if {@code array} is empty
251 */
252 public static short max(short... array) {
253 checkArgument(array.length > 0);
254 short max = array[0];
255 for (int i = 1; i < array.length; i++) {
256 if (array[i] > max) {
257 max = array[i];
258 }
259 }
260 return max;
261 }
262
263 /**
264 * Returns the values from each provided array combined into a single array.
265 * For example, {@code concat(new short[] {a, b}, new short[] {}, new
266 * short[] {c}} returns the array {@code {a, b, c}}.
267 *
268 * @param arrays zero or more {@code short} arrays
269 * @return a single array containing all the values from the source arrays, in
270 * order
271 */
272 public static short[] concat(short[]... arrays) {
273 int length = 0;
274 for (short[] array : arrays) {
275 length += array.length;
276 }
277 short[] result = new short[length];
278 int pos = 0;
279 for (short[] array : arrays) {
280 System.arraycopy(array, 0, result, pos, array.length);
281 pos += array.length;
282 }
283 return result;
284 }
285
286 /**
287 * Returns a big-endian representation of {@code value} in a 2-element byte
288 * array; equivalent to {@code
289 * ByteBuffer.allocate(2).putShort(value).array()}. For example, the input
290 * value {@code (short) 0x1234} would yield the byte array {@code {0x12,
291 * 0x34}}.
292 *
293 * <p>If you need to convert and concatenate several values (possibly even of
294 * different types), use a shared {@link java.nio.ByteBuffer} instance, or use
295 * {@link com.google.common.io.ByteStreams#newDataOutput()} to get a growable
296 * buffer.
297 */
298 @GwtIncompatible("doesn't work")
299 public static byte[] toByteArray(short value) {
300 return new byte[] {
301 (byte) (value >> 8),
302 (byte) value};
303 }
304
305 /**
306 * Returns the {@code short} value whose big-endian representation is
307 * stored in the first 2 bytes of {@code bytes}; equivalent to {@code
308 * ByteBuffer.wrap(bytes).getShort()}. For example, the input byte array
309 * {@code {0x54, 0x32}} would yield the {@code short} value {@code 0x5432}.
310 *
311 * <p>Arguably, it's preferable to use {@link java.nio.ByteBuffer}; that
312 * library exposes much more flexibility at little cost in readability.
313 *
314 * @throws IllegalArgumentException if {@code bytes} has fewer than 2
315 * elements
316 */
317 @GwtIncompatible("doesn't work")
318 public static short fromByteArray(byte[] bytes) {
319 checkArgument(bytes.length >= BYTES,
320 "array too small: %s < %s", bytes.length, BYTES);
321 return fromBytes(bytes[0], bytes[1]);
322 }
323
324 /**
325 * Returns the {@code short} value whose byte representation is the given 2
326 * bytes, in big-endian order; equivalent to {@code Shorts.fromByteArray(new
327 * byte[] {b1, b2})}.
328 *
329 * @since 7.0
330 */
331 @GwtIncompatible("doesn't work")
332 public static short fromBytes(byte b1, byte b2) {
333 return (short) ((b1 << 8) | (b2 & 0xFF));
334 }
335
336 private static final class ShortConverter
337 extends Converter<String, Short> implements Serializable {
338 static final ShortConverter INSTANCE = new ShortConverter();
339
340 @Override
341 protected Short doForward(String value) {
342 return Short.decode(value);
343 }
344
345 @Override
346 protected String doBackward(Short value) {
347 return value.toString();
348 }
349
350 @Override
351 public String toString() {
352 return "Shorts.stringConverter()";
353 }
354
355 private Object readResolve() {
356 return INSTANCE;
357 }
358 private static final long serialVersionUID = 1;
359 }
360
361 /**
362 * Returns a serializable converter object that converts between strings and
363 * shorts using {@link Short#decode} and {@link Short#toString()}.
364 *
365 * @since 16.0
366 */
367 @Beta
368 public static Converter<String, Short> stringConverter() {
369 return ShortConverter.INSTANCE;
370 }
371
372 /**
373 * Returns an array containing the same values as {@code array}, but
374 * guaranteed to be of a specified minimum length. If {@code array} already
375 * has a length of at least {@code minLength}, it is returned directly.
376 * Otherwise, a new array of size {@code minLength + padding} is returned,
377 * containing the values of {@code array}, and zeroes in the remaining places.
378 *
379 * @param array the source array
380 * @param minLength the minimum length the returned array must guarantee
381 * @param padding an extra amount to "grow" the array by if growth is
382 * necessary
383 * @throws IllegalArgumentException if {@code minLength} or {@code padding} is
384 * negative
385 * @return an array containing the values of {@code array}, with guaranteed
386 * minimum length {@code minLength}
387 */
388 public static short[] ensureCapacity(
389 short[] array, int minLength, int padding) {
390 checkArgument(minLength >= 0, "Invalid minLength: %s", minLength);
391 checkArgument(padding >= 0, "Invalid padding: %s", padding);
392 return (array.length < minLength)
393 ? copyOf(array, minLength + padding)
394 : array;
395 }
396
397 // Arrays.copyOf() requires Java 6
398 private static short[] copyOf(short[] original, int length) {
399 short[] copy = new short[length];
400 System.arraycopy(original, 0, copy, 0, Math.min(original.length, length));
401 return copy;
402 }
403
404 /**
405 * Returns a string containing the supplied {@code short} values separated
406 * by {@code separator}. For example, {@code join("-", (short) 1, (short) 2,
407 * (short) 3)} returns the string {@code "1-2-3"}.
408 *
409 * @param separator the text that should appear between consecutive values in
410 * the resulting string (but not at the start or end)
411 * @param array an array of {@code short} values, possibly empty
412 */
413 public static String join(String separator, short... array) {
414 checkNotNull(separator);
415 if (array.length == 0) {
416 return "";
417 }
418
419 // For pre-sizing a builder, just get the right order of magnitude
420 StringBuilder builder = new StringBuilder(array.length * 6);
421 builder.append(array[0]);
422 for (int i = 1; i < array.length; i++) {
423 builder.append(separator).append(array[i]);
424 }
425 return builder.toString();
426 }
427
428 /**
429 * Returns a comparator that compares two {@code short} arrays
430 * lexicographically. That is, it compares, using {@link
431 * #compare(short, short)}), the first pair of values that follow any
432 * common prefix, or when one array is a prefix of the other, treats the
433 * shorter array as the lesser. For example, {@code [] < [(short) 1] <
434 * [(short) 1, (short) 2] < [(short) 2]}.
435 *
436 * <p>The returned comparator is inconsistent with {@link
437 * Object#equals(Object)} (since arrays support only identity equality), but
438 * it is consistent with {@link Arrays#equals(short[], short[])}.
439 *
440 * @see <a href="http://en.wikipedia.org/wiki/Lexicographical_order">
441 * Lexicographical order article at Wikipedia</a>
442 * @since 2.0
443 */
444 public static Comparator<short[]> lexicographicalComparator() {
445 return LexicographicalComparator.INSTANCE;
446 }
447
448 private enum LexicographicalComparator implements Comparator<short[]> {
449 INSTANCE;
450
451 @Override
452 public int compare(short[] left, short[] right) {
453 int minLength = Math.min(left.length, right.length);
454 for (int i = 0; i < minLength; i++) {
455 int result = Shorts.compare(left[i], right[i]);
456 if (result != 0) {
457 return result;
458 }
459 }
460 return left.length - right.length;
461 }
462 }
463
464 /**
465 * Returns an array containing each value of {@code collection}, converted to
466 * a {@code short} value in the manner of {@link Number#shortValue}.
467 *
468 * <p>Elements are copied from the argument collection as if by {@code
469 * collection.toArray()}. Calling this method is as thread-safe as calling
470 * that method.
471 *
472 * @param collection a collection of {@code Number} instances
473 * @return an array containing the same values as {@code collection}, in the
474 * same order, converted to primitives
475 * @throws NullPointerException if {@code collection} or any of its elements
476 * is null
477 * @since 1.0 (parameter was {@code Collection<Short>} before 12.0)
478 */
479 public static short[] toArray(Collection<? extends Number> collection) {
480 if (collection instanceof ShortArrayAsList) {
481 return ((ShortArrayAsList) collection).toShortArray();
482 }
483
484 Object[] boxedArray = collection.toArray();
485 int len = boxedArray.length;
486 short[] array = new short[len];
487 for (int i = 0; i < len; i++) {
488 // checkNotNull for GWT (do not optimize)
489 array[i] = ((Number) checkNotNull(boxedArray[i])).shortValue();
490 }
491 return array;
492 }
493
494 /**
495 * Returns a fixed-size list backed by the specified array, similar to {@link
496 * Arrays#asList(Object[])}. The list supports {@link List#set(int, Object)},
497 * but any attempt to set a value to {@code null} will result in a {@link
498 * NullPointerException}.
499 *
500 * <p>The returned list maintains the values, but not the identities, of
501 * {@code Short} objects written to or read from it. For example, whether
502 * {@code list.get(0) == list.get(0)} is true for the returned list is
503 * unspecified.
504 *
505 * @param backingArray the array to back the list
506 * @return a list view of the array
507 */
508 public static List<Short> asList(short... backingArray) {
509 if (backingArray.length == 0) {
510 return Collections.emptyList();
511 }
512 return new ShortArrayAsList(backingArray);
513 }
514
515 @GwtCompatible
516 private static class ShortArrayAsList extends AbstractList<Short>
517 implements RandomAccess, Serializable {
518 final short[] array;
519 final int start;
520 final int end;
521
522 ShortArrayAsList(short[] array) {
523 this(array, 0, array.length);
524 }
525
526 ShortArrayAsList(short[] array, int start, int end) {
527 this.array = array;
528 this.start = start;
529 this.end = end;
530 }
531
532 @Override public int size() {
533 return end - start;
534 }
535
536 @Override public boolean isEmpty() {
537 return false;
538 }
539
540 @Override public Short get(int index) {
541 checkElementIndex(index, size());
542 return array[start + index];
543 }
544
545 @Override public boolean contains(Object target) {
546 // Overridden to prevent a ton of boxing
547 return (target instanceof Short)
548 && Shorts.indexOf(array, (Short) target, start, end) != -1;
549 }
550
551 @Override public int indexOf(Object target) {
552 // Overridden to prevent a ton of boxing
553 if (target instanceof Short) {
554 int i = Shorts.indexOf(array, (Short) target, start, end);
555 if (i >= 0) {
556 return i - start;
557 }
558 }
559 return -1;
560 }
561
562 @Override public int lastIndexOf(Object target) {
563 // Overridden to prevent a ton of boxing
564 if (target instanceof Short) {
565 int i = Shorts.lastIndexOf(array, (Short) target, start, end);
566 if (i >= 0) {
567 return i - start;
568 }
569 }
570 return -1;
571 }
572
573 @Override public Short set(int index, Short element) {
574 checkElementIndex(index, size());
575 short oldValue = array[start + index];
576 // checkNotNull for GWT (do not optimize)
577 array[start + index] = checkNotNull(element);
578 return oldValue;
579 }
580
581 @Override public List<Short> subList(int fromIndex, int toIndex) {
582 int size = size();
583 checkPositionIndexes(fromIndex, toIndex, size);
584 if (fromIndex == toIndex) {
585 return Collections.emptyList();
586 }
587 return new ShortArrayAsList(array, start + fromIndex, start + toIndex);
588 }
589
590 @Override public boolean equals(Object object) {
591 if (object == this) {
592 return true;
593 }
594 if (object instanceof ShortArrayAsList) {
595 ShortArrayAsList that = (ShortArrayAsList) object;
596 int size = size();
597 if (that.size() != size) {
598 return false;
599 }
600 for (int i = 0; i < size; i++) {
601 if (array[start + i] != that.array[that.start + i]) {
602 return false;
603 }
604 }
605 return true;
606 }
607 return super.equals(object);
608 }
609
610 @Override public int hashCode() {
611 int result = 1;
612 for (int i = start; i < end; i++) {
613 result = 31 * result + Shorts.hashCode(array[i]);
614 }
615 return result;
616 }
617
618 @Override public String toString() {
619 StringBuilder builder = new StringBuilder(size() * 6);
620 builder.append('[').append(array[start]);
621 for (int i = start + 1; i < end; i++) {
622 builder.append(", ").append(array[i]);
623 }
624 return builder.append(']').toString();
625 }
626
627 short[] toShortArray() {
628 // Arrays.copyOfRange() is not available under GWT
629 int size = size();
630 short[] result = new short[size];
631 System.arraycopy(array, start, result, 0, size);
632 return result;
633 }
634
635 private static final long serialVersionUID = 0;
636 }
637 }